//------------------------------------------------------------------------------
// Keil Software, Inc.
// 
// Project:  Cygnal 8051F000 I2C Example Program
//
// Filename:  Cygnal_I2C_Example_Program.c
// Version:  1.0.0
// Description: This file contains example code that will communicate to a 
//    serial EEPROM using I2C.  Data will be printed over the
//    serial port.
//
// Copyright 2000 - Keil Software, Inc.
// All rights reserved.
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
// Header files
//------------------------------------------------------------------------------
#include <REG51F020.H>       // Header file for the Cygnal 8051F0X0
#include <STDIO.H>        // Header file for standard I/O

struct time{unsigned char hour;
            unsigned char min;
            unsigned char second;
            };
struct date {unsigned char year;
            unsigned char month;
            unsigned char day;
            };
//------------------------------------------------------------------------------
// Value Definitions
//------------------------------------------------------------------------------
#define  TRUE    0x01   // Value representing TRUE
#define  FALSE   0x00   // Value representing FALSE
#define  ON      0x01   // Value representing ON
#define  OFF     0x00   // Value representing OFF
#define  HIGH    0x01   // Value representing ON
#define  LOW     0x00   // Value representing OFF

#define  DELAY_1MS_COUNT   750
#define  DELAY_WRITE       5     // approx. 5 ms delay write time (about 1000 cycles / ms)

//------------------------------------------------------------------------------
// Macros
//------------------------------------------------------------------------------
           // Get high byte macro
#define high_byte(x)  ((x & 0xFF00) >> 8)

//------------------------------------------------------------------------------
// I2C Bus (SMBus) register bit definitions
//------------------------------------------------------------------------------
sbit  BUS_BUSY   = 0xC7;   // SM Bus Busy (bit 7)
sbit  BUS_EN     = 0xC6;   // SM Bus Enable (bit 6)
sbit  BUS_START  = 0xC5;   // SM Bus Start (bit 5)
sbit  BUS_STOP   = 0xC4;   // SM Bus Stop (bit 4)
sbit  BUS_INT    = 0xC3;   // SM Bus Interrupt (bit 3)
sbit  BUS_AA     = 0xC2;   // SM Bus ACK (bit 2)
sbit  BUS_FTE    = 0xC1;   // SM Bus Clock timeout - high (bit 1)
sbit  BUS_TOE    = 0xC0;   // SM Bus Clock timeout - low (bit 0)

sbit scl = P0^3;
sbit sda = P0^2;

//------------------------------------------------------------------------------
// Rerserve Interrupt vector space (the 8051F000 has an IV table from 0x03 to 0xAB)
//------------------------------------------------------------------------------
unsigned char code iv_table [0xB0] _at_ 0x0003;

//------------------------------------------------------------------------------
// Function Prototypes
//------------------------------------------------------------------------------
void write_byte (unsigned char data_out,unsigned char ICaddr,unsigned int address);
unsigned char read_byte (unsigned char ICaddr,unsigned int address);
void i2c_write (unsigned char output_data);
unsigned char i2c_read (void);
void delay_time (unsigned int time_end);
void i2c_start (void);
unsigned char  i2c_stop_and_read (void);
void repeated_i2c_start_and_write (unsigned char output_data);
void i2c_stop_and_write (unsigned char output_data);
unsigned char Exchange_highlow(unsigned char car);
void Write2200(struct date d,struct time t);
//********************************************************************************

//------------------------------------------------------------------------------
// I2C Peripheral Function Prototypes
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
// Procedure: write_byte
// Inputs:  data out, address
// Outputs:  none
// Description: Writes a byte to the EEPROM given the address 
//------------------------------------------------------------------------------
void write_byte (unsigned char data_out,unsigned char ICaddr,unsigned int address)
{
unsigned char EA_BK;
EA_BK=EA;
EA=0;
    i2c_start();       // Send start signal
    i2c_write(ICaddr<<1);                 // Send identifier I2C address
    i2c_write(high_byte(address));    // Send address to EEPROM
    i2c_write((unsigned char)address);   // Send address to EEPROM
    i2c_stop_and_write(data_out);        // Send low byte to EEPROM
    delay_time(DELAY_WRITE);          // Delay a period of time to write
EA=EA_BK;
}

//------------------------------------------------------------------------------
// Procedure: read_byte
// Inputs:  address
// Outputs:  none
// Description: Reads a byte from the EEPROM given the address 
//------------------------------------------------------------------------------
unsigned char read_byte (unsigned char ICaddr,unsigned int address)
{
unsigned char data_in;
unsigned char EA_BK;
EA_BK=EA;
EA=0;
	i2c_start();                        // Send start signal
	i2c_write(ICaddr<<1);               // Send identifer I2C address
	i2c_write(high_byte(address));      // Send address to EEPROM
	repeated_i2c_start_and_write((unsigned char)address);     
	i2c_write(ICaddr*2+1);              // Send identifer I2C address
	data_in = i2c_stop_and_read();      // Read byte, send stop signal
EA=EA_BK;
return data_in;                 
}


//------------------------------------------------------------------------------
// Routine: i2c_start
// Inputs:  none
// Outputs: none
// Purpose: Sends I2C Start Trasfer - State "B"
//------------------------------------------------------------------------------
void i2c_start (void)
{
 BUS_STOP = 0;
 while (BUS_BUSY);       // Wait until we are clear to write
 BUS_START = TRUE;       // Perform I2C start
 while (!BUS_INT);       // Wait until start sent
 BUS_START = FALSE;      // Reset I2C start
 BUS_INT = 0;            // Clear SI
}

//------------------------------------------------------------------------------
//  Routine: repeated_i2c_start_and_write
// Inputs:  none
// Outputs: none
// Purpose: Sends I2C Start Trasfer - State "B"
//------------------------------------------------------------------------------
void repeated_i2c_start_and_write (unsigned char output_data)
{
 BUS_START = TRUE;          // Perform I2C start
 SMB0DAT = output_data;     // Put data into buffer
 while (!BUS_INT);          // Wait unitl we are done with send
 BUS_INT = 0;               // Clear SI
 BUS_START = FALSE;         // Reset I2C start
 while (!BUS_INT);          // Wait unitl we are done with reset
 BUS_INT = 0;               // Clear SI
}

//------------------------------------------------------------------------------
//  Routine: i2c_stop_and_write
// Inputs:  output byte
// Outputs: none
// Purpose: Sends I2C Stop Trasfer - State "C" (also sends last byte)
//------------------------------------------------------------------------------
void i2c_stop_and_write (unsigned char output_data)
{
 BUS_STOP = TRUE;           // Perform I2C stop
 SMB0DAT = output_data;     // Put data into buffer
 while (!BUS_INT);          // Wait unitl we are done with send
 BUS_INT = 0;               // Clear SI
}

//------------------------------------------------------------------------------
//  Routine: i2c_stop_and_read
// Inputs:  none
// Outputs: input byte
// Purpose: Sends I2C Stop Trasfer - State "C" (also reads last byte)
//------------------------------------------------------------------------------
unsigned char i2c_stop_and_read (void)
{
 unsigned char input_data;

 BUS_STOP = TRUE;      // Perform I2C stop
 while (!BUS_INT);      // Wait until we have data to read
 input_data = SMB0DAT;     // Read the data
 BUS_INT = 0;       // Clear SI
 return input_data;
}

//------------------------------------------------------------------------------
//  Routine: i2c_write
// Inputs:  output byte
// Outputs: none
// Purpose: Writes data over the I2C bus
//------------------------------------------------------------------------------
void i2c_write (unsigned char output_data)
{
 SMB0DAT = output_data;     // Put data into buffer
 while (!BUS_INT);      // Wait unitl we are done with send
 BUS_INT = 0;       // Clear SI
}

//------------------------------------------------------------------------------
//  Routine: i2c_read
// Inputs:  none
// Outputs: input byte
// Purpose: Reads data from the I2C bus
//------------------------------------------------------------------------------
unsigned char i2c_read (void)
{
 unsigned char input_data;
 while (!BUS_INT);      // Wait until we have data to read
 input_data = SMB0DAT;     // Read the data
 BUS_INT = 0;       // Clear SI
 return input_data;
}


////////////////////////////////////////////////////////////////////////////////
// Routine: delay_time
// Inputs:  counter value to stop delaying
// Outputs: none
// Purpose: To pause execution for pre-determined time
////////////////////////////////////////////////////////////////////////////////
void delay_time (unsigned int time_end)
{
unsigned int i,j;
for(i=time_end;i>0;i--)
    {for(j=DELAY_1MS_COUNT;j>0;j--){}}
}

//********************************** SD2200 *******************************************
void Write2200(struct date d,struct time t)
{
                                                        // Send repeated start signal
d.year=Exchange_highlow(d.year);                        //year
d.month=Exchange_highlow(d.month);                      //mon
d.day=Exchange_highlow(d.day);                          //day
                                 
t.hour=Exchange_highlow(t.hour|0x40);                   //hour
t.min=Exchange_highlow(t.min);                          //min

i2c_start();                                            // Send start signal
i2c_write(0x64);                                        // Send identifer I2C address
i2c_write(d.year);i2c_write(d.month);i2c_write(d.day);
i2c_write(0);                                           //week;
i2c_write(t.hour);i2c_write(t.min); 
i2c_stop_and_write(0);                                  //second
}

//read date and time from sd2200
void Read2200(unsigned char *d,unsigned char *t)
{
unsigned char car;
i2c_start();                                            // Send start signal
i2c_write(0x65);                                        // Send identifer I2C address
                                                        // Send repeated start signal
car=i2c_read();*d=Exchange_highlow(car);                //year
car=i2c_read();*(d+1)=Exchange_highlow(car);            //mon
car=i2c_read();*(d+2)=Exchange_highlow(car);            //day
car=i2c_read();                                         //week;
car=i2c_read();*t=Exchange_highlow(car);*t=(*t)&0x3f;   //hour
car=i2c_read();*(t+1)=Exchange_highlow(car);            //min
car=i2c_stop_and_read();*(t+2)=Exchange_highlow(car);   //second
}

unsigned char Exchange_highlow(unsigned char car)
{
unsigned i,c=0;
for(i=0;i<8;i++)
   {c=c*2+(car-2*(car>>1));car=car>>1;}
return c;
}
